package service

import (
	"crypto/rand"
	"encoding/hex"
	"errors"
	"fmt"
	"time"

	"markedit/internal/model"

	"github.com/golang-jwt/jwt/v5"
	"github.com/sirupsen/logrus"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

type UserService struct {
	db        *gorm.DB
	logger    *logrus.Logger
	jwtSecret string
}

func NewUserService(db *gorm.DB, logger *logrus.Logger, jwtSecret string) *UserService {
	return &UserService{
		db:        db,
		logger:    logger,
		jwtSecret: jwtSecret,
	}
}

// Register 用户注册
func (s *UserService) Register(req *model.UserRegisterRequest) (*model.User, error) {
	// 检查用户名是否已存在
	var existingUser model.User
	if err := s.db.Where("username = ? OR email = ?", req.Username, req.Email).First(&existingUser).Error; err == nil {
		return nil, errors.New("用户名或邮箱已存在")
	}

	// 生成用户ID
	userID, err := s.generateID()
	if err != nil {
		return nil, fmt.Errorf("生成用户ID失败: %v", err)
	}

	// 加密密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
	if err != nil {
		return nil, fmt.Errorf("密码加密失败: %v", err)
	}

	// 创建用户
	user := &model.User{
		ID:        userID,
		Username:  req.Username,
		Email:     req.Email,
		Password:  string(hashedPassword),
		CreatedAt: time.Now(),
		UpdatedAt: time.Now(),
		IsActive:  true,
	}

	if err := s.db.Create(user).Error; err != nil {
		return nil, fmt.Errorf("创建用户失败: %v", err)
	}

	s.logger.Infof("用户注册成功: %s", user.Username)
	return user, nil
}

// Login 用户登录
func (s *UserService) Login(req *model.UserLoginRequest) (*model.UserLoginResponse, error) {
	// 查找用户
	var user model.User
	if err := s.db.Where("username = ? OR email = ?", req.Username, req.Username).First(&user).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("用户名或密码错误")
		}
		return nil, fmt.Errorf("查询用户失败: %v", err)
	}

	// 检查用户是否激活
	if !user.IsActive {
		return nil, errors.New("用户账户已被禁用")
	}

	// 验证密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)); err != nil {
		return nil, errors.New("用户名或密码错误")
	}

	// 生成JWT令牌
	token, err := s.generateJWT(user.ID)
	if err != nil {
		return nil, fmt.Errorf("生成令牌失败: %v", err)
	}

	// 创建会话
	session := &model.Session{
		ID:        fmt.Sprintf("sess_%s", s.generateRandomString(16)),
		UserID:    user.ID,
		Token:     token,
		ExpiresAt: time.Now().Add(24 * time.Hour), // 24小时过期
		CreatedAt: time.Now(),
		IsActive:  true,
	}

	if err := s.db.Create(session).Error; err != nil {
		s.logger.Warnf("创建会话失败: %v", err)
	}

	// 更新最后登录时间
	user.LastLogin = time.Now()
	s.db.Save(&user)

	s.logger.Infof("用户登录成功: %s", user.Username)
	return &model.UserLoginResponse{
		User:  user,
		Token: token,
	}, nil
}

// GetUserByID 根据ID获取用户
func (s *UserService) GetUserByID(userID string) (*model.User, error) {
	var user model.User
	if err := s.db.Where("id = ? AND is_active = ?", userID, true).First(&user).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("用户不存在")
		}
		return nil, fmt.Errorf("查询用户失败: %v", err)
	}
	return &user, nil
}

// UpdateUser 更新用户信息
func (s *UserService) UpdateUser(userID string, req *model.UserUpdateRequest) (*model.User, error) {
	user, err := s.GetUserByID(userID)
	if err != nil {
		return nil, err
	}

	// 检查用户名和邮箱是否已被其他用户使用
	if req.Username != "" && req.Username != user.Username {
		var existingUser model.User
		if err := s.db.Where("username = ? AND id != ?", req.Username, userID).First(&existingUser).Error; err == nil {
			return nil, errors.New("用户名已存在")
		}
		user.Username = req.Username
	}

	if req.Email != "" && req.Email != user.Email {
		var existingUser model.User
		if err := s.db.Where("email = ? AND id != ?", req.Email, userID).First(&existingUser).Error; err == nil {
			return nil, errors.New("邮箱已存在")
		}
		user.Email = req.Email
	}

	if req.Avatar != "" {
		user.Avatar = req.Avatar
	}

	user.UpdatedAt = time.Now()

	if err := s.db.Save(user).Error; err != nil {
		return nil, fmt.Errorf("更新用户失败: %v", err)
	}

	s.logger.Infof("用户信息更新成功: %s", user.Username)
	return user, nil
}

// ChangePassword 修改密码
func (s *UserService) ChangePassword(userID string, req *model.ChangePasswordRequest) error {
	user, err := s.GetUserByID(userID)
	if err != nil {
		return err
	}

	// 验证旧密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword)); err != nil {
		return errors.New("旧密码错误")
	}

	// 加密新密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
	if err != nil {
		return fmt.Errorf("密码加密失败: %v", err)
	}

	// 更新密码
	user.Password = string(hashedPassword)
	user.UpdatedAt = time.Now()

	if err := s.db.Save(user).Error; err != nil {
		return fmt.Errorf("更新密码失败: %v", err)
	}

	// 使所有会话失效
	s.db.Model(&model.Session{}).Where("user_id = ?", userID).Update("is_active", false)

	s.logger.Infof("用户密码修改成功: %s", user.Username)
	return nil
}

// ValidateToken 验证JWT令牌
func (s *UserService) ValidateToken(tokenString string) (string, error) {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return []byte(s.jwtSecret), nil
	})

	if err != nil {
		return "", err
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
		userID, ok := claims["user_id"].(string)
		if !ok {
			return "", errors.New("invalid token claims")
		}

		// 检查会话是否有效
		var session model.Session
		if err := s.db.Where("token = ? AND is_active = ? AND expires_at > ?", 
			tokenString, true, time.Now()).First(&session).Error; err != nil {
			return "", errors.New("session expired or invalid")
		}

		return userID, nil
	}

	return "", errors.New("invalid token")
}

// Logout 用户登出
func (s *UserService) Logout(token string) error {
	// 使会话失效
	if err := s.db.Model(&model.Session{}).Where("token = ?", token).Update("is_active", false).Error; err != nil {
		return fmt.Errorf("登出失败: %v", err)
	}

	s.logger.Info("用户登出成功")
	return nil
}

// generateJWT 生成JWT令牌
func (s *UserService) generateJWT(userID string) (string, error) {
	claims := jwt.MapClaims{
		"user_id": userID,
		"exp":     time.Now().Add(24 * time.Hour).Unix(),
		"iat":     time.Now().Unix(),
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString([]byte(s.jwtSecret))
}

// generateID 生成唯一ID
func (s *UserService) generateID() (string, error) {
	bytes := make([]byte, 16)
	if _, err := rand.Read(bytes); err != nil {
		return "", err
	}
	return fmt.Sprintf("user_%s", hex.EncodeToString(bytes)), nil
}

// generateRandomString 生成随机字符串
func (s *UserService) generateRandomString(length int) string {
	bytes := make([]byte, length)
	rand.Read(bytes)
	return hex.EncodeToString(bytes)[:length]
}